#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
脚本名称: QQ 自动修炼脚本 v0.14
脚本作者：艾雪 & Bing Copilet (改进：Claude)
Python 版本: 3.x
编码: UTF-8
"""

import time
import psutil
import pyautogui as gui
import pyperclip as clip
import win32gui
import random
import logging
import gc
from typing import Optional
from dataclasses import dataclass
from datetime import datetime

@dataclass
class Config:
    """配置类，集中管理所有配置项"""
    robot_name: str = "@汐汐酱"
    command_msg: str = "/修炼"
    tupo_msg: str = "直接突破"
    tupo_interval: int = 999999999
    bcast_interval: int = 100
    sleep_time: float = 0.02
    retry_limit: int = 3
    log_file: str = "autoxixi.log"

class AutoXiXi:
    def __init__(self):
        self.config = Config()
        self.count = 0
        self._setup_logging()
        self._setup_gui()
        
    def _setup_logging(self):
        """配置日志系统"""
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(self.config.log_file, encoding='utf-8'),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger(__name__)
        
    def _setup_gui(self):
        """配置GUI自动化设置"""
        gui.FAILSAFE = False
        
    def is_qq_running(self) -> bool:
        """检查QQ是否在运行"""
        try:
            return any(proc.name() == 'QQ.exe' for proc in psutil.process_iter(['name']))
        except Exception as e:
            self.logger.error(f"检查QQ运行状态时出错: {e}")
            return False
            
    def switch_qq(self):
        """切换到QQ窗口"""
        try:
            time.sleep(self.config.sleep_time)
            gui.hotkey("ctrl", "alt", "x")
        except Exception as e:
            self.logger.error(f"切换QQ窗口时出错: {e}")
            
    def alt_tab(self):
        """切换窗口"""
        try:
            time.sleep(self.config.sleep_time)
            gui.hotkey("alt", "tab")
        except Exception as e:
            self.logger.error(f"Alt+Tab切换失败: {e}")
            
    def safe_clipboard_operation(self, text: str):
        """安全的剪贴板操作"""
        retry_count = 0
        while retry_count < self.config.retry_limit:
            try:
                clip.copy(text)
                return True
            except Exception as e:
                retry_count += 1
                self.logger.warning(f"剪贴板操作失败 (尝试 {retry_count}/{self.config.retry_limit}): {e}")
                time.sleep(0.5)
        return False
        
    def send_xiulian(self):
        """发送修炼命令"""
        try:
            if not self.safe_clipboard_operation(self.config.robot_name):
                return False
                
            gui.hotkey("ctrl", "v")
            time.sleep(self.config.sleep_time * 10)
            
            for _ in range(1):  # 重复发送以确保成功
                gui.press("enter")
                time.sleep(self.config.sleep_time)
                
            if not self.safe_clipboard_operation(self.config.command_msg):
                return False
                
            gui.hotkey("ctrl", "v")
            time.sleep(self.config.sleep_time * 10)
            
            for _ in range(3):  # 确保命令发送成功
                gui.press("enter")
                time.sleep(self.config.sleep_time)
                
            return True
        except Exception as e:
            self.logger.error(f"发送修炼命令时出错: {e}")
            return False
            
    def send_breakthrough(self):
        """发送突破命令"""
        try:
            if not self.safe_clipboard_operation(self.config.robot_name):
                return False
                
            gui.hotkey("ctrl", "v")
            time.sleep(self.config.sleep_time * 10)
            gui.press("enter")
            
            if not self.safe_clipboard_operation(self.config.tupo_msg):
                return False
                
            gui.hotkey("ctrl", "v")
            time.sleep(self.config.sleep_time * 10)
            
            for _ in range(4):
                gui.press("enter")
                time.sleep(self.config.sleep_time)
                
            return True
        except Exception as e:
            self.logger.error(f"发送突破命令时出错: {e}")
            return False
            
    def send_count_broadcast(self):
        """发送计数广播"""
        try:
            count_msg = f"------ AutoXixi已助您完成 {self.count} 次修炼！------"
            if not self.safe_clipboard_operation(count_msg):
                return False
                
            gui.hotkey("ctrl", "v")
            time.sleep(self.config.sleep_time)
            
            for _ in range(2):
                gui.press("enter")
                time.sleep(self.config.sleep_time)
                
            return True
        except Exception as e:
            self.logger.error(f"发送计数广播时出错: {e}")
            return False
            
    def countdown(self, seconds: int):
        """倒计时"""
        try:
            while seconds > 0:
                mins, secs = divmod(seconds, 60)
                print(f'\r等待下次修炼 {mins:02d}:{secs:02d}', end='')
                time.sleep(1)
                seconds -= 1
            print('\r', end='')
        except Exception as e:
            self.logger.error(f"倒计时出错: {e}")
            
    def get_active_window_title(self) -> Optional[str]:
        """获取当前活动窗口标题"""
        try:
            handle = win32gui.GetForegroundWindow()
            return win32gui.GetWindowText(handle)
        except Exception as e:
            self.logger.error(f"获取窗口标题时出错: {e}")
            return None
            
    def perform_cultivation(self):
        """执行修炼流程"""
        try:
            if not self.send_xiulian():
                return False
                
            if self.count > 0:
                if self.count % self.config.tupo_interval == 0:
                    time.sleep(1)
                    self.send_breakthrough()
                    
                if self.count % self.config.bcast_interval == 0:
                    time.sleep(1)
                    self.send_count_broadcast()
                    
            return True
        except Exception as e:
            self.logger.error(f"执行修炼流程时出错: {e}")
            return False
            
    def cleanup(self):
        """清理资源"""
        try:
            clip.copy('')  # 清空剪贴板
            gc.collect()   # 强制垃圾回收
        except Exception as e:
            self.logger.error(f"清理资源时出错: {e}")
            
    def run(self):
        """主运行循环"""
        self.logger.info("启动自动修炼脚本")
        
        while True:
            try:
                if not self.is_qq_running():
                    self.logger.error("QQ未运行，请先启动QQ")
                    break
                    
                window_title = self.get_active_window_title()
                
                if window_title == "QQ":
                    self.logger.debug("当前窗口是QQ，开始修炼")
                    success = self.perform_cultivation()
                else:
                    self.logger.debug("切换到QQ窗口")
                    self.switch_qq()
                    success = self.perform_cultivation()
                    self.alt_tab()
                    
                if success:
                    self.count += 1
                    self.logger.info(f"完成第 {self.count} 次修炼")
                    
                # 添加随机等待时间，避免被检测
                wait_time = 61 + random.uniform(0, 1)
                self.countdown(wait_time)
                
                # 定期清理资源
                if self.count % 10 == 0:
                    self.cleanup()
                    
            except Exception as e:
                self.logger.error(f"运行时发生错误: {e}")
                time.sleep(5)  # 错误发生时等待一段时间再继续
                
if __name__ == "__main__":
    bot = AutoXiXi()
    bot.run()